//https://gist.github.com/iwillspeak/cd27b740d658a6f38c8c

#include <string>
#include <iostream>

#define CAPTURE_TOKEN(t) \
  token->value = std::string(ts, te-ts); \
  token->type = Token::t

%%{
  machine ExampleLexer;

  main := |*

    digit+ => {
      CAPTURE_TOKEN(Num);
      fbreak;
    };

    alpha (alpha | digit) * => {
      CAPTURE_TOKEN(Var);
      fbreak;
    };
    
    '+' => {
        CAPTURE_TOKEN(Plus);
        fbreak;
    };

    space+;
  *|;
}%%

%%write data;

struct Token
{
    enum TokenType {
        Var,
        Num,
        Plus,
        End,
        None
    };

    TokenType type;
    std::string value;
};

class Lexer
{
public:
    Lexer(std::string input)
      : buffer(input) {

        %%write init;

        // set up the buffer here
        p = buffer.c_str();
        pe = p + buffer.size();
        eof = pe;
    }

    Token* next() {
        auto token = new Token();
    
        token->type = Token::None;
    
        do {
    
            if (cs >= ExampleLexer_first_final) {
                token->type = Token::End;
            }
    
            %%write exec;
            
            if (cs == ExampleLexer_error) {
                token->type = Token::None;
                return token;
            }
            
        } while (token->type == Token::None);
    
        return token;
    }

private:
    // buffer state
    const char* p, * pe, * eof;
    // current token
    const char* ts, * te;
    // machine state
    int act, cs, top, stack[1];

    std::string buffer;
};


int main(int argc, const char* argv[]) {

	auto lex = Lexer("test + 123");
	Token* token;

	do {
	   token = lex.next();

	   std::cout << "<" << token->value << ">" << std::endl;

	} while (token->type != Token::None &&
	         token->type != Token::End);
}
